package wikiPhilia;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Set;

import codeanticode.glgraphics.GLGraphics;

import processing.core.PApplet;
import processing.core.PVector;
import wpRelations.TsvTable;

public class WikiPhilia_002 extends PApplet {
	TsvTable testTable;
	String fileName = "Coby_Miller_stuff3.tsv";
	HashMap<String,WNode> myNodes = new HashMap<String,WNode>();
	ArrayList<WEdge> myEdges = new ArrayList<WEdge>();
	ArrayList<WNode> myNodeArray;
	WNode centerNode;
	WArticle centerArticle;
	public static int maxLinkCount = 0;
	int counter = 0;
	
	public void setup() {
		//size(800,800,GLGraphics.GLGRAPHICS);
		size(800,800,P3D);
		testTable = new TsvTable(this, fileName);
		centerArticle = new WArticle(this, "Coby_Miller");
		System.out.println("The table " + fileName + " has " + testTable.getRowCount() + " rows.");
		System.out.println("The table " + fileName + " has " + testTable.data[0].length + " coloumns.");
		noFill();
		noStroke();
		int k = 1;
		addNodesEdges(testTable, 0, k);
		counter = k;
	}
	
	public void draw() {
		addNodesEdges(testTable, counter, counter+1);
		counter++;
		centerNode = myNodes.get("Coby_Miller");
		//setPositions(300f,100,101);
		//setPositions(200f,myEdges.size(),myNodeArray.size()+2); //sieht lustig aus
		//setPositions(200f,counter,maxLinkCount); //auch...
		setPositions(200f,counter-1,counter);
		System.out.println("Nodes altogether: " + myNodeArray.size());
		System.out.println("Edges altogether: " + myEdges.size());
		background(0);
		//translate(center.getPos().x,center.getPos().y);
		translate(width/2,height/2);
		rotateX(map(mouseY,0,height,0,TWO_PI));
		rotateY(map(mouseX,0,width,0,TWO_PI));
		//translate(-(width/2-center.getPos().x),-(height/2-center.getPos().y));
		for(int i = 0; i < myNodeArray.size(); i++) {
			myNodeArray.get(i).update();
			myNodeArray.get(i).display();
		}
		for(int i = 0; i < myEdges.size(); i++) {
			myEdges.get(i).display();
		}
		//setPositions(300f,frameCount,5+frameCount);

	}
	
	public void setPositions(float radius, int hC, int vC) {
		int nodeCount = myNodes.size();
		float myInc = 1/(float)(nodeCount);
		centerNode.setPos(new PVector(0,0,0));
		float hCycles = hC;
		float vCycles = vC;
		Set<String> myKeySet = myNodes.keySet();
		ArrayList<String> myKeyList = new ArrayList<String>(myKeySet);
		//String[] myKeyArray = (String[]) list.toArray();
		//Set myKeySet = myNodes.keySet();
		
//		for (int i = 0; i < nodeCount; i++) {
//			if (!myKeyList.get(i).equalsIgnoreCase(center.getTitle())) {
//				float lambda = TWO_PI*myInc*i;
//				float x = center.getPos().x + sin(lambda)*radius;
//				float y = 0f;
//				float z = center.getPos().z + cos(lambda)*radius;
//				myNodes.get(myKeyList.get(i)).setPos(new PVector(x,y,z));
//			}
//		}

		/*
		for (int i = 0; i < nodeCount; i++) {
			if (!myKeyList.get(i).equalsIgnoreCase(center.getTitle())) {
				float myIncH = myInc*i;
				float myIncV = myInc*i;
				float lambda = TWO_PI*myInc*i*hCycles;
				float beta = PI*myInc*i*vCycles;
				float x = center.getPos().x + sin(lambda)*cos(beta)*radius;
				float y = center.getPos().y + sin(beta)*radius;
				float z = center.getPos().z + cos(lambda)*cos(beta)*radius;
				myNodes.get(myKeyList.get(i)).setPos(new PVector(x,y,z));
			}
		}
		*/
		float minRadius = radius;
		float maxRadius = 2*radius;
		for (int i = 0; i < nodeCount; i++) {
			if (!myKeyList.get(i).equalsIgnoreCase(centerNode.getTitle())) {
				float myRadius = maxRadius - (myNodes.get(myKeyList.get(i)).getLinksCount()/(float)maxLinkCount)*(maxRadius-minRadius);
				float myIncH = myInc*i;
				float myIncV = myInc*i;
				float lambda = TWO_PI*myInc*i*hCycles;
				float beta = TWO_PI*myInc*i*vCycles;
				float x = centerNode.getcPos().x + sin(lambda)*cos(beta)*myRadius;
				float y = centerNode.getcPos().y + sin(beta)*myRadius;
				float z = centerNode.getcPos().z + cos(lambda)*cos(beta)*myRadius;
				myNodes.get(myKeyList.get(i)).setPos(new PVector(x,y,z));
			}
		}
		
	}

	public void addNodesEdges(TsvTable sourceTable, int startIndex, int endIndex) {
		if (myNodes == null) myNodes = new HashMap<String,WNode>();
		if (myEdges == null) myEdges = new ArrayList<WEdge>();
		for (int i = startIndex; i < min(sourceTable.getRowCount(),endIndex); i++) {
			String fromTitle = testTable.getString(i, 0);
			String toTitle = testTable.getString(i, 1);
			String fromType = testTable.getString(i, 2);
			String toType = testTable.getString(i, 3);
			int iFromType = WNode.TYPE_ARTICLE;
			int iToType = WNode.TYPE_ARTICLE;
			if (fromType == "person") iFromType = WNode.TYPE_PERSON;
			if (fromType == "non_person") iFromType = WNode.TYPE_NON_PERSON;
			if (fromType == "category") iFromType = WNode.TYPE_CATEGORY;			
			if (toType == "person") iToType = WNode.TYPE_PERSON;
			if (toType == "non_person") iToType = WNode.TYPE_NON_PERSON;
			if (toType == "category") iToType = WNode.TYPE_CATEGORY;
			WNode fromNode = new WNode(this, fromTitle, iFromType);
			WNode toNode = new WNode(this, toTitle, iToType);
			if ( !myNodes.containsKey(fromTitle) && !myNodes.containsKey(toTitle)) {
				myNodes.put(fromTitle,fromNode);
				myNodes.put(toTitle,toNode);
				myNodes.get(fromTitle).incLinks();
				myNodes.get(toTitle).incBacklinks();
				myEdges.add(new WEdge(this,myNodes.get(fromTitle),myNodes.get(toTitle)));
				if (fromNode.getType()==WNode.TYPE_CATEGORY) myEdges.get(myEdges.size()-1).setType(WEdge.TYPE_CONTAINS);
			} else if ( myNodes.containsKey(fromTitle) && !myNodes.containsKey(toTitle)) {
				fromNode.incLinks();
				myNodes.put(toTitle,toNode);
				myEdges.add(new WEdge(this,myNodes.get(fromTitle),myNodes.get(toTitle)));
				myNodes.get(fromTitle).incLinks();
				myNodes.get(toTitle).incBacklinks();
				if (fromNode.getType()==WNode.TYPE_CATEGORY) myEdges.get(myEdges.size()-1).setType(WEdge.TYPE_CONTAINS);
			} else if (!myNodes.containsKey(fromTitle) && myNodes.containsKey(toTitle)) {
				myNodes.put(fromTitle,fromNode);
				myEdges.add(new WEdge(this,myNodes.get(fromTitle),myNodes.get(toTitle)));
				if (fromNode.getType()==WNode.TYPE_CATEGORY) myEdges.get(myEdges.size()-1).setType(WEdge.TYPE_CONTAINS);
				myNodes.get(fromTitle).incLinks();
				myNodes.get(toTitle).incBacklinks();
			} else {
				//TODO: check if it is a loop
				int in = -1;
				int out = -1;
				
				for (int j = 0; j < myEdges.size(); j++) {
					if(myEdges.get(j).getFromNode().getTitle().equalsIgnoreCase(toTitle) && myEdges.get(j).getToNode().getTitle().equalsIgnoreCase(fromTitle)) in = j;
				}
					if (in > -1 ) {
					myEdges.get(in).setType(WEdge.TYPE_LOOP);
				} else {
					myNodes.get(fromTitle).incLinks();
					myNodes.get(toTitle).incBacklinks();				
					myEdges.add(new WEdge(this,myNodes.get(fromTitle),myNodes.get(toTitle)));
					if (fromNode.getType()==WNode.TYPE_CATEGORY) myEdges.get(myEdges.size()-1).setType(WEdge.TYPE_CONTAINS);
				}
			}
		}
		myNodeArray = new ArrayList<WNode>(myNodes.values());
		for (int i = 0; i < myNodeArray.size(); i++) {
			if (maxLinkCount < myNodeArray.get(i).getLinksCount()) maxLinkCount =myNodeArray.get(i).getLinksCount();
		}

	}
	
	public void setNodesEdges(int begin, int end) {
		myNodes = new HashMap<String,WNode>();
		myEdges = new ArrayList<WEdge>();
		for (int i = begin; i < min(testTable.getRowCount(),end); i++) {
			String fromTitle = testTable.getString(i, 0);
			String toTitle = testTable.getString(i, 1);
			String fromType = testTable.getString(i, 2);
			String toType = testTable.getString(i, 3);
			int iFromType = WNode.TYPE_ARTICLE;
			int iToType = WNode.TYPE_ARTICLE;
			if (fromType == "person") iFromType = WNode.TYPE_PERSON;
			if (fromType == "non_person") iFromType = WNode.TYPE_NON_PERSON;
			if (fromType == "category") iFromType = WNode.TYPE_CATEGORY;			
			if (toType == "person") iToType = WNode.TYPE_PERSON;
			if (toType == "non_person") iToType = WNode.TYPE_NON_PERSON;
			if (toType == "category") iToType = WNode.TYPE_CATEGORY;
			WNode fromNode = new WNode(this, fromTitle, iFromType);
			WNode toNode = new WNode(this, toTitle, iToType);
						
			if ( !myNodes.containsKey(fromTitle) && !myNodes.containsKey(toTitle)) {
				myNodes.put(fromTitle,fromNode);
				myNodes.put(toTitle,toNode);
				myNodes.get(fromTitle).incLinks();
				myNodes.get(toTitle).incBacklinks();
				myEdges.add(new WEdge(this,myNodes.get(fromTitle),myNodes.get(toTitle)));
			} else if ( myNodes.containsKey(fromTitle) && !myNodes.containsKey(toTitle)) {
				fromNode.incLinks();
				myNodes.put(toTitle,toNode);
				myEdges.add(new WEdge(this,myNodes.get(fromTitle),myNodes.get(toTitle)));
				myNodes.get(fromTitle).incLinks();
				myNodes.get(toTitle).incBacklinks();
			} else if (!myNodes.containsKey(fromTitle) && myNodes.containsKey(toTitle)) {
				
				myNodes.put(fromTitle,fromNode);
				myEdges.add(new WEdge(this,myNodes.get(fromTitle),myNodes.get(toTitle)));
				myNodes.get(fromTitle).incLinks();
				myNodes.get(toTitle).incBacklinks();
			} else {
				//TODO: check if it is a loop
				int in = -1;
				int out = -1;
				
				for (int j = 0; j < myEdges.size(); j++) {
				//	if(myEdges.get(j).getFromNode().equals(myNodes.get(fromTitle)) && myEdges.get(j).getToNode().equals(myNodes.get(toTitle))) out = j;
				//	if(myEdges.get(j).getFromNode().equals(myNodes.get(toTitle)) && myEdges.get(j).getToNode().equals(myNodes.get(fromTitle))) in = j;
					//if(myEdges.get(j).getFromNode().getTitle().equalsIgnoreCase(fromTitle) && myEdges.get(j).getToNode().getTitle().equalsIgnoreCase(toTitle)) out = j;
					if(myEdges.get(j).getFromNode().getTitle().equalsIgnoreCase(toTitle) && myEdges.get(j).getToNode().getTitle().equalsIgnoreCase(fromTitle)) in = j;
				}
				//if (in > -1 && out > -1) {
					if (in > -1 ) {
					myEdges.get(in).setType(WEdge.TYPE_LOOP);
					//myEdges.get(out).setType(WEdge.TYPE_LOOP);
				} else {
					myNodes.get(fromTitle).incLinks();
					myNodes.get(toTitle).incBacklinks();				
					myEdges.add(new WEdge(this,myNodes.get(fromTitle),myNodes.get(toTitle)));
				}
			}
		}

	}	
	
	public static void main(String[] args) {
		PApplet.main(new String[] { wikiPhilia.WikiPhilia_002.class.getName() });
	}
	
}